package gutils

import (
	"reflect"
)

type MSet struct {
	tp reflect.Type
	m  map[interface{}]struct{}
}

func NewMSet(tp reflect.Type) Set {
	return &MSet{
		tp: tp,
		m:  make(map[interface{}]struct{}),
	}
}

func (this *MSet) Size() int {
	return len(this.m)
}
func (this *MSet) Empty() bool {
	return len(this.m) == 0
}
func (this *MSet) Contains(i interface{}) bool {
	_, ok := this.m[i]
	return ok
}
func (this *MSet) ToSlice() interface{} {
	st := reflect.SliceOf(this.tp)
	s := reflect.MakeSlice(st, 0, this.Size())
	for k, _ := range this.m {
		s = reflect.Append(s, reflect.ValueOf(k))
	}
	return s.Interface()
}
func (this *MSet) Add(i interface{}) bool {
	if !checkType(i, this.tp) {
		return false
	}
	if _, ok := this.m[i]; !ok {
		this.m[i] = struct{}{}
		return true
	}
	return false
}
func (this *MSet) Remove(i interface{}) bool {
	if !checkType(i, this.tp) {
		return false
	}
	if _, ok := this.m[i]; ok {
		delete(this.m, i)
		return true
	}
	return false
}

func (this *MSet) Range(f func(interface{})) {
	for k, _ := range this.m {
		f(k)
	}
}

func checkType(i interface{}, tp reflect.Type) bool {
	return tp == reflect.TypeOf(i)
}
